package rmmk.algorithms.similarityMeasures;

import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import rmmk.algorithms.similarityMeasures.abstraction.AbstractSimilarityMeasure;
import rmmk.framework.datasources.Document;

public class NgramMeasure extends AbstractSimilarityMeasure{

	Logger logger = LoggerFactory.getLogger(NgramMeasure.class);
	int min,max;

	public NgramMeasure(int min, int max) {
		this.min = min;
		this.max = max;
	}
	
	@Override
	public Double[] doCalculate(Document input, Document document) {
		Double[] result = new Double[1];
		double similarity = 0.0;

		int skippedWordsCount = 0;
		ArrayList<String> inputWords = input.getExtractedWords();
		for (String word : inputWords) {
			if (word.length() < min) {
				logger.debug("skipped!");
				skippedWordsCount++;
				continue;
			}
			double maxSimilarity = 0.0;
			for (String word2 : document.getExtractedWords()) {
				double similarityOfWords = getSimilarity(word, word2, min, max);
				if (similarityOfWords > maxSimilarity)
					maxSimilarity = similarityOfWords;
			}
			similarity += maxSimilarity;
		}

		result[0] = similarity / (inputWords.size() - skippedWordsCount);
		return result;
	}

	private Double getSimilarity(String word1, String word2, int min, int max) {

		double similarity = 0.0;
		
		String longerWord = word1.length() > word2.length() ? word1 : word2;
		String shorterWord = word1.length() <= word2.length() ? word1 : word2;
		logger.debug("longer word: "+longerWord);
		logger.debug("shorter word: "+shorterWord);
		
		if (min > shorterWord.length()) {
			return 0.0;
		}
		
		if (max > shorterWord.length()) {
			max = shorterWord.length();
		}
		
		CharSequence ngram;
		for (int i = min; i <= max; i++) {
			for (int j = 0; j < shorterWord.length() - i+1; j++) {
				ngram = shorterWord.subSequence(j, j + i);
				logger.debug("ngram: "+ngram+"");
				if (longerWord.contains(ngram)) {
					similarity += 1.0;
				}
			}
		}
		int allVariations = ((longerWord.length() - min + 1)
				* (longerWord.length() - min + 2) - (longerWord.length()
				- max + 1)
				* (longerWord.length() - max));
		double f = 2.0 / allVariations;
		logger.debug("all variations: "+allVariations);
		similarity = similarity * f;
		logger.debug("podobienstwo ngram dla: " + word1 + " i " + word2 + " wynosi: "
				+ similarity);
		return similarity;
	}

	@Override
	public int getSimilarityMeasureSize() {
		return 1;
	}
}